package com.sunpy.niohttp.annotation.impl;

import com.sunpy.niohttp.annotation.RespBodyJson;
import com.sunpy.niohttp.annotation.ReqBody;
import com.sunpy.niohttp.etc.Worker;
import com.sunpy.niohttp.model.*;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import javax.validation.constraints.NotNull;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class RequestProxy implements MethodInterceptor {

    @NotNull
    private SunpyRequest sunpyRequest;
    @NotNull
    private SunpyResponse sunpyResponse;

    public RequestProxy(SunpyRequest sunpyRequest, SunpyResponse sunpyResponse) {
        this.sunpyRequest = sunpyRequest;
        this.sunpyResponse = sunpyResponse;
    }

    public <T> T getProxy(Class<T> clazz) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(new RequestProxy(sunpyRequest, sunpyResponse));
        return (T) enhancer.create();
    }

    public void doServiceByProxy() {
        MethodMapping methodMapping = AnnotationImpl.findMappingMethod(sunpyRequest.getUri(), sunpyRequest.getMethod());

        if (methodMapping == null) {
            sunpyResponse.setCode("404");
            sunpyResponse.setStatus("Bad Request");
            StringBuilder sb = new StringBuilder();
            sb.append("request path ");
            sb.append(sunpyRequest.getUri());
            sb.append(" not exist, 404 error");
            sunpyResponse.setBody(sb.toString());
            // 完善响应头
            new Worker().packResponse(sunpyRequest, sunpyResponse);

            return;
        }

        try {
            MethodInfo methodInfo = methodMapping.getMethodInfo();
            // 获取需要代理的类
            Class clazz = Class.forName(methodInfo.getPackageName()+ "." +methodInfo.getClazzName());

            List<ParamInfo> paramInfoList = methodInfo.getParamInfoList();
            List<Object> paramValues = methodInfo.getParamValues();

            for (int i = 0 ; i < paramInfoList.size() ; i++) {
                ParamInfo paramInfo = paramInfoList.get(i);
                if (paramInfo.isAnnotationFlag()) {
                    AnnotationInfo annotationInfo = paramInfo.getAnnotationInfo();

                    if (ReqBody.class.getName().equals(annotationInfo.getAnnotationName()) &&
                            sunpyRequest.getHeaders().get("Content-Type").trim() != null) {
                        paramValues.set(i, sunpyRequest.getBody());
                    }
                }
            }

            // 获取需要代理的方法
            Method method = clazz.getMethod(methodInfo.getMethodName(), methodInfo.getParamTypes().toArray(new Class<?>[paramInfoList.size()]));

            // 执行代理的方法
            Object obj = method.invoke(new RequestProxy(sunpyRequest, sunpyResponse).getProxy(clazz), paramValues.toArray());
            List<AnnotationInfo> annotationInfoList = methodInfo.getAnnotationInfoList();

            annotationInfoList.forEach(annotationInfo -> {
                if (annotationInfo.getAnnotationName().equals(RespBodyJson.class.getName())) {
                    Map<String, String> headers = new HashMap<>();
                    headers.put("Content-Type", "application/json;charset=UTF-8");
                    sunpyResponse.setHeaders(headers);
                }
            });

            sunpyResponse.setCode("200");
            sunpyResponse.setStatus("OK");
            sunpyResponse.setBody(obj);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 完善响应头
        new Worker().packResponse(sunpyRequest, sunpyResponse);


    }

    private void before() {
    }

    public void after() {
    }

    /**
     * 重写方法拦截在方法前和方法后加入业务
     * Object obj为目标对象
     * Method method为目标方法
     * Object[] params 为参数，
     * MethodProxy proxy CGlib方法代理对象
     */
    @Override
    public Object intercept(Object obj,
                            Method method,
                            Object[] args,
                            MethodProxy methodProxy) throws Throwable {

        before();
        Object result = methodProxy.invokeSuper(obj, args);
        after();
        return result;
    }

    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.sunpy.niohttp.user.UserRequestController");
        Method method = clazz.getMethod("getUserInfo");
        Object obj = method.invoke(clazz.newInstance());
        System.out.println(obj);
    }

}
